import { Injectable, UseFilters } from '@nestjs/common';
import { JwtService } from '@nestjs/jwt';
import { InjectRepository } from '@nestjs/typeorm';
import { equals, isNil } from 'ramda';
import { HttpExceptionFilter } from 'src/common/http-exception.filter';
import { errorState, getPagination, successState, throwHttp } from 'src/utlis';
import { isTrue } from 'src/utlis/tools';
import { Between, Connection, In, Like, Repository, TreeRepository } from 'typeorm';
import {
  CreateRoleDto,
  GetRolePageDto,
  RoleAuthConfigDto,
  UpdateRoleDto,
} from './dto/role.dto';
import { RoleEntity, RoleType } from './entities/role.entity';
import { TokenDto } from 'src/common/auth/constants';
import { Status } from 'src/dictionaries/index.enum';
import { MenuEntity } from '../menu/entities/menu.entity';
import { IdDto } from 'src/common/dto/dto';

@Injectable()
export class RoleService {
  constructor(
    @InjectRepository(RoleEntity)
    private readonly roleEntityRepository: Repository<RoleEntity>,
    @InjectRepository(MenuEntity)
    private readonly menuRepository: TreeRepository<MenuEntity>,
    private readonly jwtService: JwtService,
    private readonly connection: Connection,
  ) { }
  /** 角色列表 */
  async getRolePage(params: GetRolePageDto) {
    try {
      const {
        createTimeStart,
        createTimeEnd,
        updateTimeEnd,
        updateTimeStart,
        rolename,
        status,
      } = params;
      const { pageSize, pageNum } = getPagination({
        pageSize: params.pageSize,
        pageNum: params.pageNum,
      });
      const where: GetRolePageDto = {
        rolename: Like(`%${rolename || ''}%`),
        status,
      };
      // 时间筛选
      if (!isNil(createTimeStart) && !isNil(createTimeEnd)) {
        where.createDate = Between(createTimeStart, createTimeEnd);
      }
      // 更新时间筛选
      if (!isNil(updateTimeStart) && !isNil(updateTimeEnd)) {
        where.updateDate = Between(updateTimeStart, updateTimeEnd);
      }
      const [data, total] = await this.roleEntityRepository.findAndCount({
        where,
        cache: true,
        skip: pageNum * pageSize,
        take: pageSize,
        order: { createDate: 'DESC' },
      });
      return {
        data,
        total,
        pageSize,
        pageNum: pageNum + 1,
      };
    } catch (error) {
      throwHttp(error.message);
    }
  }
  /** 获取角色详情 */
  @UseFilters(new HttpExceptionFilter())
  async getRoleInfo(where) {
    try {
      return await this.roleEntityRepository.findOne({
        where,
      });
    } catch (error) {
      throwHttp(error.message);
    }
  }
  async createRole(body: CreateRoleDto, userId: number) {
    try {
      const { rolename, description, menu, status, type } = body;
      const data = await this.getRoleInfo({ rolename });
      if (isTrue(data)) {
        throwHttp('已有相同名称的角色');
        return;
      }
      const role = new RoleEntity();
      role.rolename = rolename;
      role.description = description;
      role.status = status;
      role.type = type;
      role.menu = menu;
      role.createById = userId;
      const result = await this.roleEntityRepository.manager.save(role);
      return {
        msg: isTrue(result) ? '角色创建成功' : '角色创建失败',
        data: result,
      }
    } catch (error) {
      throwHttp(error.message);
    }
  }
  /** 更新角色信息 */
  @UseFilters(new HttpExceptionFilter())
  async updateRole(body: UpdateRoleDto) {
    try {
      const { id, rolename, description, status, menu } = body;
      const data = await this.getRoleInfo({ id });
      if (!isTrue(data)) {
        throwHttp('角色不存在');
      }
      const { affected } = await this.roleEntityRepository
        .createQueryBuilder()
        .update(RoleEntity)
        .set({
          rolename, description, status, menu
        })
        .where('id = :id', { id })
        .execute();
      if (affected) {
        return {
          msg: '修改成功',
          data
        };
      }
      throwHttp('修改失败');
    } catch (error) {
      throwHttp(error.message);
    }
  }
  /** 获取用户权限 */
  async getUserRolePermissions(rolesId) {
    try {
      const role = await this.getRoleInfo({
        id: rolesId,
        status: Status.ENABLED,
      });
      // 查询所有菜单及其按钮
      const menus = await this.menuRepository.findTrees({
        relations: ['menuButton', 'children'], // 加载子菜单
      });
      if (equals(role.type, RoleType.ordinary)) {
        // 构造一个 Map 用于快速查找 menuId 对应的按钮权限
        const menuDataMap = new Map(
          role.menu.map((item) => [item.menuId, item.menuButtonId])
        );
        // 递归过滤树
        const filterTree = (menuList) => {
          return menuList?.filter(item => menuDataMap.get(item.id)).map(item => {
            item.children = filterTree(item.children)
            const allowedButtons: any = menuDataMap.get(item.id) || [];
            item.menuButton = item.menuButton?.filter(button => allowedButtons.includes(button.id))
            return item
          })
        };

        role.menu = this.sortTree(filterTree(menus))
      } else {
        role.menu = this.sortTree(menus)
      }
      return role;
    } catch (error) {
      throwHttp(error.message);
    }
  }
  // 递归排序分类树
  private sortTree(categories: MenuEntity[]): MenuEntity[] {
    return categories
      .sort((a, b) => a.sort - b.sort) // 根据 order 字段排序
      .map(menu => {
        if (menu.children) {
          menu.children = this.sortTree(menu.children); // 递归排序子分类
        }
        return menu;
      });
  }

  /** 删除角色 */
  @UseFilters(new HttpExceptionFilter())
  async deleteMenu({ id }: IdDto) {
    try {
      const data = await this.menuRepository.findOne({
        where: { id },
        cache: true,
      });
      if (!isTrue(data)) {
        throwHttp('角色不存在');
        return;
      }
      await this.menuRepository.softDelete(id);
      return '删除成功';
    } catch (error) {
      throwHttp(error.message);
    }
  }
  async addRoleIfNotExists(userId: number) {
    const data = await this.roleEntityRepository.findOne({
      where: {
        rolename: '超级管理员'
      }
    })
    if (!data) {
      await this.createRole({
        rolename: '超级管理员',
        status: Status.ENABLED,
        type: RoleType.super,
        description: '系统创建',
        menu: [],
      }, userId)
      const data = await this.roleEntityRepository.findOne({
        where: {
          rolename: '超级管理员'
        }
      })
      return data
    }
    return data
  }
}
